package org.tony.nio.demo.selectors;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class SelectedSockets
{
	private static final int	DEFAULT_PORT	= 8989;
	private Selector			selector		= null;

	private List<SocketChannel>	clients			= new ArrayList<SocketChannel>();

	/**
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception
	{
		new SelectedSockets().service(args);
	}

	public void service(String args[]) throws Exception
	{
		int port = DEFAULT_PORT;
		if (args.length == 1)
		{
			port = Integer.parseInt(args[0]);
		}

		System.out.println("Listen to service on port :" + port);
		ServerSocketChannel ssc = ServerSocketChannel.open();
		ServerSocket server = ssc.socket();
		selector = Selector.open();
		server.bind(new InetSocketAddress(port));
		ssc.configureBlocking(false);
		ssc.register(selector, SelectionKey.OP_ACCEPT);
		while (true)
		{
			int n = selector.select();
			if (n == 0)
			{
				continue;
			}
			Iterator<SelectionKey> iter = selector.selectedKeys().iterator();
			while (iter.hasNext())
			{
				SelectionKey key = iter.next();
				if (key.isAcceptable())
				{
					// new incoming connection
					ServerSocketChannel sscChannel = (ServerSocketChannel) key.channel();
					SocketChannel socket = sscChannel.accept();
					registerChannel(selector, socket, SelectionKey.OP_READ);
					clients.add(socket);
					sayHello(socket);
					System.out.println("a client connect to server");
				}

				if (key.isReadable())
				{
					readDataFromSocket(key);
				}
				iter.remove();
			}
		}
	}

	private void registerChannel(Selector selector , SelectableChannel channel , int ops)
	{
		if (channel == null)
		{
			return;
		}
		try
		{
			channel.configureBlocking(false);
			channel.register(selector, ops);
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}

	}

	private ByteBuffer	buffer	= ByteBuffer.allocate(1024);

	protected void readDataFromSocket(SelectionKey keys) throws Exception
	{
		SocketChannel sc = (SocketChannel) keys.channel();
		buffer.clear();
		int count = 0;
		while ((count = sc.read(buffer)) > 0)
		{
			if (count < 4)
			{
				continue;
			}
			buffer.flip();
			System.out.println(buffer.getChar());
			break;
		}
		if (count == -1)
		{
			keys.cancel();
			sc.close();
			return;
		}
		for (SocketChannel s : clients)
		{
			if (s.isConnected())
			{
				buffer.clear();
				buffer.put(new String("\r\nHi,I am from <" + sc.socket().getLocalAddress() + ">\r\n").getBytes());
				buffer.flip();
				s.write(buffer);
			}
		}
	}

	private void sayHello(SocketChannel channel) throws Exception
	{
		buffer.clear();
		buffer.put("Hello,This is Server.What can i do for you?\r\n".getBytes());
		buffer.flip();
		channel.write(buffer);
		buffer.clear();
	}
}
